﻿/*
 * Author: Duncan Jenkins
 *  
 * Description: Color Segmentation using Mean-Shift (Currently not operational - or even really using mean-shift)
 * */

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;

namespace LibraryCS {
    public class MeanShift : VisionAlgorithm {
        int KernelSize;
        double Difference;

        public MeanShift(String name) : base(name) { }

        public override Bitmap DoAlgorithm(Bitmap sourceImage) {
            VImage ops = new VImage(sourceImage);
            VImage destOps = new VImage(sourceImage.Width, sourceImage.Height);
            int radius = KernelSize / 2;

            // Testing wether iterating multiple times does more, not so far (unless doing 111 Kernel, Diff 100)
            for (int loop = 0; loop < 1; loop++) {
                // Loop through the image, skipping the borders
                for (int y = radius; y < ops.Height - radius; y++) {
                    for (int x = radius; x < ops.Width - radius; x++) {
                        int index = y * ops.Width + x;
                        int red = ops.RedPixels[index];
                        int green = ops.GreenPixels[index];
                        int blue = ops.BluePixels[index];
                        Mean mean = new Mean(red, green, blue, 0);

                        for (int ky = 0 - radius; ky <= radius; ky++) {
                            for (int kx = 0 - radius; kx <= radius; kx++) {
                                int kindex = (ky + y) * ops.Width + (kx + x);
                                int kred = ops.RedPixels[kindex];
                                int kgreen = ops.GreenPixels[kindex];
                                int kblue = ops.BluePixels[kindex];

                                // Calculate the distance of the current pixel to the pixel we are processing using Euclidean Distance
                                double distance = Math.Sqrt((Math.Pow((kred - mean.Red), 2.0)) + (Math.Pow((kgreen - mean.Green), 2.0)) + (Math.Pow((kblue - mean.Blue), 2.0)));
                                //Debug.WriteLine("Distance: " + distance);
                                if (distance < Difference) {
                                    mean.addPixel(kindex, kred, kgreen, kblue);
                                }
                            }
                        }

                        // Calculate the mean of the pixels with distance
                        mean.calculateMean();

                        // Replace the values of the pixels with the mean
                        for (int i = 0; i < mean.pixels.Count; i++) {
                            int mindex = mean.pixels[i];
                            destOps.RedPixels[mindex] = (byte)mean.Red;
                            destOps.GreenPixels[mindex] = (byte)mean.Green;
                            destOps.BluePixels[mindex] = (byte)mean.Blue;
                        }
                    }
                }

                // Apply the changes
                destOps.ApplyPixelChanges();
            }

            return destOps.localImage;
        }

        #region GUI Functions

        public override List<System.Windows.Forms.Control> createControls() {
            List<Control> Controls = new List<Control>();

            // Create a Label indictating the type of setting this is
            Label klb = new Label();
            klb.AutoSize = true;
            klb.Text = "Kernel Size";
            klb.Name = "lbKernelSize";

            // Create a TextBox Control for setting the number of means
            TextBox ktb = new TextBox();
            ktb.Name = "tbKernelSize";
            ktb.AcceptsReturn = false;
            ktb.MaxLength = 3;
            ktb.Multiline = false;
            ktb.Size = new Size(50, 25);

            // Create a Label indictating the type of setting this is
            Label dlb = new Label();
            dlb.AutoSize = true;
            dlb.Text = "Difference";
            dlb.Name = "lbDifference";

            // Create a TextBox Control for setting the number of means
            TextBox dtb = new TextBox();
            dtb.Name = "tbDifference";
            dtb.AcceptsReturn = false;
            dtb.MaxLength = 3;
            dtb.Multiline = false;
            dtb.Size = new Size(50, 25);

            // Add the controls to the list
            Controls.Add(ktb);
            Controls.Add(klb);
            Controls.Add(dtb);
            Controls.Add(dlb);

            // Return the list
            return Controls;
        }

        public override void setSettings(List<object> settings) {
            KernelSize = Int32.Parse(((TextBox)settings[0]).Text);
            Difference = Double.Parse(((TextBox)settings[1]).Text);
            Debug.WriteLine("Settings entered: " + KernelSize);
            Debug.WriteLine("Settings entered: " + Difference);
        }

        #endregion
    }
}
